import datetime
import multiprocessing
import threading
from object.single.parts import SingleData, SingleIntegrateProcess, Fruit
from object.unit import Engine, Data, Order
from conf.conf import ori_value_val
import os
from object.single.task import start_process_v2_alone


class SingleEngine(Engine):
    def __init__(self):
        super().__init__()
        self.variable_key = ""
        self.variable_value = None
        self.data_ins = None
        self.integrate_ins = None
        self.fruit_ins = None
        self.com_order_ls = []  # 多进行回测后生成的全量订单列表数据
        self.process_number = None

        self.queue = multiprocessing.Queue()  # 创建一个队列用于存储结果

    def add_data_ins(self):
        self.data_ins = SingleData(self.variable_value)

        pass

    def get_process_number(self):
        """获取当前系统支持的进程数"""
        self.process_number = os.cpu_count()

    def gen_com_data(self):
        """调用数据实例的生成全量数据方法处理数据相关逻辑"""
        self.data_ins = SingleData(self.variable_value)
        # 生成全量数据
        self.data_ins.gen_com_data()
        # 发起回调
        self.on_gen_com_data()
        pass

    @staticmethod
    def get_tactic_class_name(tactic_name):
        from operate.models import SgTactic
        # 根据tactic name来获取相应类的类名
        sg_tactic = SgTactic.objects.get(name=tactic_name)
        class_name = sg_tactic.class_name

        return class_name

    def extract_factor_name(self):
        """提取所有因子的名字，战法内含因子"""
        # 导入模块
        from object.single import tactic
        # 收集所有战法名
        tactics_factor_ls = []
        for tactic_name in self.variable_value["lab_var_part2_3"]["filter_ls"]:
            class_name = self.get_tactic_class_name(tactic_name)
            # 实例化该战法类，以提取其中factor_name属性
            # 实例化并关联bt_task
            cls = getattr(tactic, class_name)
            tactic_ins = cls()
            tactics_factor_ls += tactic_ins.factor_name

        for tactic_name in self.variable_value["lab_var_part2_3"]["open_ls"]:
            class_name = self.get_tactic_class_name(tactic_name)
            # 实例化该战法类，以提取其中factor_name属性
            # 实例化并关联bt_task
            cls = getattr(tactic, class_name)
            tactic_ins = cls()
            tactics_factor_ls += tactic_ins.factor_name

        for tactic_name in self.variable_value["lab_var_part2_3"]["close_ls"]:
            class_name = self.get_tactic_class_name(tactic_name)
            # 实例化该战法类，以提取其中factor_name属性
            # 实例化并关联bt_task
            cls = getattr(tactic, class_name)
            tactic_ins = cls()
            tactics_factor_ls += tactic_ins.factor_name
        # 修改variable变量的值lab_var_part2_4
        self.variable_value["lab_var_part2_4"]["tactics_factor_ls"] = sorted(list(set(tactics_factor_ls)))
        pass

    def gen_factor_com_data(self):
        """调用数据实例的生成全量因子数据方法处理数据相关逻辑"""
        # 生成全量因子数据
        self.data_ins.gen_factor_data()
        # 全量因子数据生成回调
        self.on_gen_factor()

    def init_part_5(self):
        """初始化lab_var_part2_5相应的值"""
        self.variable_value["lab_var_part2_5"]["parallel_task_count"] = self.process_number
        self.variable_value["lab_var_part2_5"]["progress"] = {}
        self.variable_value["lab_var_part2_5"]["datetime_ls"] = []
        self.variable_value["lab_var_part2_5"]["close_ls"] = []
        self.variable_value["lab_var_part2_5"]["value_ls"] = []
        self.variable_value["lab_var_part2_5"]["pos_ls"] = []
        self.variable_value["lab_var_part2_5"]["profit_ls"] = []
        self.variable_value["lab_var_part2_5"]["holding_ls"] = []
        self.variable_value["lab_var_part2_5"]["indicator_ls"] = []
        self.variable_value["lab_var_part2_5"]["describe_text"] = ""
        self.variable_value["lab_var_part2_5"]["execute"] = False

    def check_condition(self):
        """检查开始回测的条件是否充分"""
        # 前述模块的execute为True
        execute_2 = self.variable_value["lab_var_part2_2"]["execute"]
        execute_3 = self.variable_value["lab_var_part2_3"]["execute"]
        execute_4 = self.variable_value["lab_var_part2_4"]["execute"]
        if not (execute_2 and execute_3 and execute_4):
            return [False, "有未确认的模块"]
        # 全量因子数据已生成
        com_data_columns = list(self.data_ins.com_data.columns)
        factor_ls = self.variable_value["lab_var_part2_4"]["tactics_factor_ls"]
        for factor_o in factor_ls:
            if factor_o not in com_data_columns:
                return [False, "有未生成的因子"]

        # 开仓和平仓战法至少各一个
        open_ls = self.variable_value["lab_var_part2_3"]["open_ls"]
        close_ls = self.variable_value["lab_var_part2_3"]["close_ls"]
        if len(open_ls) == 0 or len(close_ls) == 0:
            return [False, "开仓或平仓战法为空"]

        return [True, "通过"]

    def gen_process_data(self):
        """调用数据实例的生成多进程数据方法处理根据进程数分割数据的相关逻辑"""
        # 生成分割后用于多进程的数据
        self.data_ins.gen_multi_data(self.process_number)

    def start_process_v2(self):
        """启动多进程"""
        from object.single.task import task, receive
        # 重置variable相关的process数据
        self.variable_value["lab_var_part2_5"]["progress"] = {}
        sorted_results = start_process_v2_alone(self.variable_value, self.data_ins, self.queue, self.process_number)
        bt_com_datetime_ls = []
        bt_com_close_ls = []
        bt_com_pos_ls = []

        for result_type, idx_addend, bt_data in sorted_results:
            bt_com_datetime_ls += bt_data[0]
            bt_com_close_ls += bt_data[1]
            bt_com_pos_ls += bt_data[2]
        close_ls = bt_com_close_ls
        pos_ls = bt_com_pos_ls
        # 先计算close_ls的一阶差分
        close_diff = [0]
        for i in range(len(close_ls)):
            if i == 0:
                continue
            close_diff.append(close_ls[i]-close_ls[i-1])
        # 将一阶差分与仓位进行点乘
        dot_mul = [a*b for a, b in zip(pos_ls, close_diff)]  # 获取了每个点对应的盈亏情况
        # 将盈亏情况进行累加获得净值序列
        total = 0
        cum_profit_ls = []
        for profit in dot_mul:
            total += profit
            cum_profit_ls.append(total)
        # 将其平移为初始值为100净值序列
        value_ls = [cum + ori_value_val for cum in cum_profit_ls]
        bt_com_value_ls = value_ls
        return [bt_com_datetime_ls, bt_com_close_ls, bt_com_pos_ls, bt_com_value_ls]

    def gen_integrate_process(self, bt_com_data):
        """进程中已经生成了每一份数据的回测数据，在此组合"""
        # 创建整合实例
        self.integrate_ins = SingleIntegrateProcess()
        # 调用整合中的函数，按照逻辑顺序调用
        self.integrate_ins.com_datetime_ls = bt_com_data[0]
        self.integrate_ins.com_close_ls = bt_com_data[1]
        self.integrate_ins.com_pos_ls = bt_com_data[2]
        self.integrate_ins.com_value_ls = bt_com_data[3]
        self.integrate_ins.save_csv()

    def gen_fruit(self):
        """根据生成的携带全量订单信息的数据自动撮合为合理的订单数据，并生成回测结果"""
        # 创建结果实例
        self.fruit_ins = Fruit(self)
        # 进行回测结果的计算，按照逻辑顺序调用
        self.fruit_ins.gen_part_node()
        self.fruit_ins.gen_trade()
        self.fruit_ins.gen_trade_chart()
        self.fruit_ins.gen_indicator()
        self.fruit_ins.gen_describe_text()
        # 生成了结果，已是回测的最后一步
        self.on_backtested()
        self.fruit_ins.save_var_json()

    def on_gen_com_data(self):
        """当生成了完整数据后，执行的回调函数"""
        # 修改variable中第三四五部分为未执行，第二部分为已执行，使得前端以不同样式显示
        self.variable_value["lab_var_part2_2"]["execute"] = True

        self.variable_value["lab_var_part2_3"]["execute"] = False
        self.variable_value["lab_var_part2_4"]["execute"] = False
        self.variable_value["lab_var_part2_5"]["execute"] = False

    def on_set_up_tactics(self):
        """当设置了战法后，执行的回调函数"""
        # 修改variable中第四五部分未未执行，第三部分为已执行，使得前端以不同样式显示
        self.variable_value["lab_var_part2_3"]["execute"] = True

        self.variable_value["lab_var_part2_4"]["execute"] = False
        self.variable_value["lab_var_part2_5"]["execute"] = False

    def on_gen_factor(self):
        """当生成了战法对应因子数据后，执行的回调函数"""
        # 修改variable中第五部分未未执行，第四部分为已执行，使得前端以不同样式显示
        self.variable_value["lab_var_part2_4"]["execute"] = True

        self.variable_value["lab_var_part2_5"]["execute"] = False

    def on_backtested(self):
        """当完成了回测，执行的回调函数"""
        # 修改variable中第五部分为已执行，使得前端以不同样式显示
        self.variable_value["lab_var_part2_5"]["execute"] = True








